#ifndef __SLIST__

#define __SLIST__

enum SListException { _EMPTYLIST, _INVALIDITERATOR };

template<typename T>
class SNode {
	T elem;	
	SNode * next;
	
	public:
		
	SNode() : next(0) {}


	SNode(T const & t, SNode<T> * n = 0) : elem(t), next(n) {}


	SNode(SNode<T> const & sn) : elem(sn.elem), next(sn.next ? new SNode<T>(*sn.next) : 0) {}
	

	~SNode() {
		if (next) delete next;
	}
	
	T const & element() const {
		return elem;
	}
	
	T & element() {
		return elem;
	}
	
	SNode * nextnode() const {
		return next;
	}
	
	SNode * & nextnode() {
		return next;
	}
};

template<typename T>
class SList {
	
	SNode<T> * head;
	SNode<T> * last;
	
	public:
	
	class SForward {
		
		SList const * me;
		
		SNode<T> * node;
		
		public:
			
		SForward() : me(0), node(0) {}
			
		SForward(SForward const & i) : me (i . me), node (i . node) {}
			
		SForward(SList const * m, SNode<T> * n) : me(m), node(n) {}
			
		~SForward() {}
			
		bool operator==(SForward const & i) const {
			return (me == i.me) && (node == i.node);
		}
		
		bool operator!=(SForward const & i) const {
			return (me != i.me) || (node != i.node);
		}
		
		T & operator*() {
			if (node)
				return node -> element();
			else
				throw _INVALIDITERATOR;
		}
		
		T & operator->() {
			if (node)
				return node -> element();
			else
				throw _INVALIDITERATOR;
		}

		SForward & operator++() {
			if (node) {
				node = node->nextnode();
				return *this;
			}
			else
				throw _INVALIDITERATOR;
		}
		
		SForward operator++(int n) {
			SForward temp(*this);
			operator++();
			return temp;
		}
		
	};
		
	SList() : head(0), last(0) {}

	SList(T const & t) : head(new SNode<T>(t, 0)), last(head) {}

	~SList() {
		delete head;
	}

	void push_back(T const & t) {
		if (last == 0) {
			last = new SNode<T>(t, 0);
			head = last;
		}
		else {
			SNode<T> * temp = new SNode<T>(t, 0);
			last -> nextnode() = temp;
			last = temp;
		}
	}

	SForward begin() const {
		return SForward(this, head);
	}

	SForward end() const {
		return SForward(this, 0);
	}

	T const & back() const {
		if (last)
			return last -> elem;
		else
			throw(_EMPTYLIST);
	}
	
	
};

#endif